"""
Created on 27-Jul-2009

@author: dexen
"""

import time
import socket

import rpyc
from rpyc.utils.logger import Logger
from dexen.system.common.excepts import DexenRegistryDiscoveryError,\
    DexenConnectionError

default_config = {
    "allow_pickle":True,
    "instantiate_custom_exceptions":True,
    "instantiate_oldstyle_exceptions":True
}

REGISTRY_PORT = 9999
MAX_SLAVE_SLOTS = 4 # The number of 

class DexenAddr(object):
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
   
    def get_conn(self, conf=default_config, timeout=10):
        start_time = time.time()
        while time.time() - start_time < timeout:
            try:
                conn = rpyc.connect(self.ip, self.port, config=conf)
                assert conn
                return conn
            except:
                #print "Couldn't connect trying again"
                time.sleep(1)
        err_msg = "Connection to ip:%s, port:%d couldn't be established."%(self.ip, self.port)
        raise DexenConnectionError(err_msg)


def get_my_ip(is_local=False):
    if is_local: return "127.0.0.1"
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        s.connect(("gmail.com", 80))
    except socket.gaierror:
        return "127.0.0.1"
    return s.getsockname()[0]

def is_local(reg_host):
    if reg_host == "local":
        return True
    return False

def is_ip_addr(host):
    temp = host.split(".")
    if len(temp) != 4:
        return False
    for elem in temp:
        if not elem.isdigit():
            return False
    return True

def get_reg_addr(reg_host, timeout=15):
    if is_ip_addr(reg_host):
        return DexenAddr(reg_host, REGISTRY_PORT)
    if is_local(reg_host):
        return DexenAddr("127.0.0.1", REGISTRY_PORT)
    if reg_host == "unassigned":
        return DexenAddr(get_my_ip(), REGISTRY_PORT)
    start_time = time.time()
    while time.time() - start_time < timeout:
        try:
            (ip, port) = rpyc.discover(reg_host, timeout=1)[0] #TODO: make sure list size is 1
            assert port == REGISTRY_PORT
            return DexenAddr(ip, port)
        except:
            time.sleep(1)
            #print "Trying to discover registry addr"
    err_msg = "Cannot connect to the server [%s].\n"%(reg_host)
    err_msg += "Please check your network settings make sure that firewall is "
    err_msg += "not the problem."
    raise DexenRegistryDiscoveryError(err_msg)
                                      
def get_svr_addr(reg_host):
    reg_addr = get_reg_addr(reg_host)
    reg_conn = reg_addr.get_conn()
    srv_addr = reg_conn.root.get_server_addr()
    srv_addr = rpyc.classic.obtain(srv_addr)
    return srv_addr

def get_svr_conn(reg_host):
    srv_addr = get_svr_addr(reg_host)
    return srv_addr.get_conn()

def get_rpyc_logger(svc_name, is_quiet):
    return Logger(svc_name, quiet=is_quiet)

class MyService(rpyc.Service):  
    def on_connect(self):
        #print "Somebody connected."
        pass
    
    def on_disconnect(self):
        #print "Somebody disconnected."
        pass
    
    def _rpyc_getattr(self, name):
        if not name.startswith("_"):
            return getattr(self, name)
        else:
            raise AttributeError("private attributes are not accessible.")
    
    def _rpyc_setattr(self, name, value):
        print "I am in setattr", name, value
        if not name.startswith("_"):
            return setattr(self, name, value)
        else:
            raise AttributeError("private data attributes cannot be set.")
    
